home *** CD-ROM | disk | FTP | other *** search
- /****************************************************************************
- *
- * $Source: /unixb/home/unixlib/source/unixlib37/src/unix/c/RCS/stat,v $
- * $Date: 1996/10/30 22:04:51 $
- * $Revision: 1.5 $
- * $State: Rel $
- * $Author: unixlib $
- *
- * $Log: stat,v $
- * Revision 1.5 1996/10/30 22:04:51 unixlib
- * Massive changes made by Nick Burret and Peter Burwood.
- *
- * Revision 1.4 1996/09/16 21:23:52 unixlib
- * CL_0002 Nick Burret
- * Minor changes to file handling
- * Change most error numbers, and use in assembler sources (SJC)
- * Various minor bug fixes and compatability changes.
- *
- * Revision 1.3 1996/07/21 22:12:31 unixlib
- * CL_0001 Nick Burret
- * Improve memory handling. Remove C++ library incompatibilities.
- * Improve file stat routines.
- *
- * Revision 1.2 1996/05/06 09:01:35 unixlib
- * Updates to sources made by Nick Burrett, Peter Burwood and Simon Callan.
- * Saved for 3.7a release.
- *
- * Revision 1.1 1996/04/19 21:35:27 simon
- * Initial revision
- *
- ***************************************************************************/
-
- static const char rcs_id[] = "$Id: stat,v 1.5 1996/10/30 22:04:51 unixlib Rel $";
-
- #include <errno.h>
- #include <time.h>
- #include <fcntl.h>
- #include <stdio.h>
- #include <unistd.h>
-
- #include <sys/types.h>
- #include <sys/dev.h>
- #include <sys/unix.h>
- #include <sys/stat.h>
- #include <sys/os.h>
- #include <sys/swis.h>
-
- static void __stat (register int *, register struct stat *);
-
- int
- stat (const char *fname, struct stat *buf)
- {
- int r[6];
- _kernel_oserror *e;
- char *file;
-
- if (!buf)
- {
- errno = EINVAL;
- return (-1);
- }
-
- file = __uname ((char *)fname, 0);
-
- if (e = os_file (0x05, file, r))
- {
- __seterr (e);
- return (-1);
- }
- if (!r[0])
- {
- errno = ENOENT;
- return (-1);
- }
-
- buf->st_dev = makedev (DEV_RISCOS, 0);
-
- __stat (r, buf);
-
- return (0);
- }
-
- int
- lstat (const char *fname, struct stat *buf)
- {
- return stat (fname, buf);
- }
-
- int
- fstat (int fd, struct stat *buf)
- {
- register struct file *f;
-
- if (!buf)
- {
- errno = EINVAL;
- return (-1);
- }
-
- if (BADF (fd))
- {
- errno = EBADF;
- return (-1);
- }
-
- f = __u->file + fd;
-
- buf->st_dev = f->dev;
-
- __stat (f->r, buf);
-
- return (0);
- }
-
- /* This function is used by __stat() and readdir(). */
-
- unsigned int
- __get_file_serial_no (char *fname)
- {
- int r[10];
- char tmp[256], *s;
- unsigned int ino;
- char *name;
-
- /* The file serial number, which distringuishes this file from
- all other files on the same device.
-
- Hash the filename to hopefully make a fairly unique number. */
-
- name = __uname (fname, 0);
-
- r[0] = 37;
- r[1] = (int)name;
- r[2] = (int)tmp;
- r[3] = r[4] = 0;
- r[5] = 255;
- ino = r[3] + r[4];
- if (!os_swi (OS_FSControl, r) && r[5] >= 0)
- {
- for (s = tmp; s[0] || s[1]; s += 2)
- ino += (s[1] == 0) ? s[0]<<5 : s[0] * s[1];
- }
- return ino;
- }
-
- static void
- __stat (register int *r, register struct stat *buf)
- {
- buf->st_ino = __get_file_serial_no ((char *)r[1]);
-
- buf->st_mode = ((r[5] & 0001) << 8) | ((r[5] & 0002) << 6) |
- ((r[5] & 0020) >> 2) | ((r[5] & 0040) >> 4);
-
- switch (r[0])
- {
- case 1:
- buf->st_mode |= S_IFREG;
- break;
- case 2: /* Normal directory */
- buf->st_mode |= S_IFDIR | 0700; /* FS bug */
- break;
- case 3: /* Image directory (RISC OS 3 and above) */
- buf->st_mode |= S_IFDIR | ((buf->st_mode & 0400) >> 2); /* FS bug */
- break;
- }
-
- switch (major (buf->st_dev))
- {
- case DEV_TTY:
- buf->st_mode |= S_IFCHR;
- break;
- case DEV_PIPE:
- buf->st_mode |= 0;
- break;
- }
-
- /* The number of hard links to the file. For RISC OS, there is only
- one hard link since only one directory can point to the file.
- Symbolic links are not counted in the total. */
- buf->st_nlink = 1;
- buf->st_uid = 1;
- buf->st_gid = 1;
- buf->st_rdev = 0;
- buf->st_size = r[4];
- /* Disc space that the file occupies, measured in units of 512
- byte blocks. */
- buf->st_nblocks = r[4] / 512;
- /* Optimal block size for reading or writing this file, in bytes.
- Since sector sizes are usually 512 or 1024 bytes on RISC OS
- disc formats, we'll safely assume a block size of 1024. */
- buf->st_blksize = 1024;
-
- if ((((unsigned int) r[2]) >> 20) == 0xfff) /* date stamped file */
- {
- register unsigned int t1, t2, tc;
-
- t1 = (unsigned int) (r[3]);
- t2 = (unsigned int) (r[2] & 0xff);
-
- tc = 0x6e996a00U;
- if (t1 < tc)
- t2--;
- t1 -= tc;
- t2 -= 0x33; /* 00:00:00 Jan. 1 1970 = 0x336e996a00 */
-
- t1 = (t1 / 100) + (t2 * 42949673U); /* 0x100000000 / 100 = 42949672.96 */
- t1 -= (t2 / 25); /* compensate for .04 error */
-
- buf->st_atime = buf->st_mtime = buf->st_ctime = t1;
- }
- else
- buf->st_atime = buf->st_mtime = buf->st_ctime = 0;
- }
-